package eva.savant.core.view.util;

import eva.savant.core.CoreBean;
import eva.savant.core.service.NameService;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.FactoryFinder;
import java.io.PrintWriter;
import java.io.StringWriter;

public class FacesUtils {

    public static CoreBean getCoreBean() {

        return (CoreBean) getManagedBean(NameService.CORE_BEAN);
    }

	public static ServletContext getServletContext() {

		return (ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext();
	}

    public static Object getManagedBean(String beanName) {

        FacesContext fc = FacesContext.getCurrentInstance();

        ELContext elc = fc.getELContext();

        ExpressionFactory ef = fc.getApplication().getExpressionFactory();

        ValueExpression ve = ef.createValueExpression(elc, getJsfEl(beanName), Object.class);

        try { return ve.getValue(elc);

        } catch (Exception e) { System.out.println("could not get value for bean " + beanName); return null; }
    }

    public static void resetManagedBean(String beanName) {

        FacesContext fc = FacesContext.getCurrentInstance();

        ELContext elc = fc.getELContext();

        ExpressionFactory ef = fc.getApplication().getExpressionFactory();

        ef.createValueExpression(elc, getJsfEl(beanName), Object.class).setValue(elc, null);
    }

	public static void setManagedBeanInSession(String beanName, Object managedBean) {

		FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(beanName, managedBean);
	}

    public static void setRequestAttribute(String key , Object data) {

        ((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).setAttribute(key,data);
    }

	public static String getRequestParameter(String name) {

		return FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(name);
	}

	public static void addInfoMessage(String msg) {

		addInfoMessage(null, msg);
	}
	
	public static void addInfoMessage(String clientId, String msg) {

		FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg));
	}

    public static void addWarnMessage(String clientId, String msg) { //Add information message to a specific client

        FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_WARN, msg, msg));
    }

    public static void addErrorMessage(Exception e) {

        FacesUtils.getHttpSession(false).setAttribute("log-exception",toString(e));

        String causa= e.getCause() != null?  e.getCause().getMessage()  :  "";

        causa= causa.length() > 0? " CAUSA:  " + causa : causa;

        addErrorMessage(null,"ERROR: " + e.getMessage()+causa);

        e.printStackTrace();
    }

	public static void addErrorMessage(String msg) {

		addErrorMessage(null, msg);
	}

	public static void addErrorMessage(String clientId, String msg) {

		FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg));
	}

	private static Application getApplication() {

		ApplicationFactory appFactory = (ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);

		return appFactory.getApplication(); 
	}

	public static HttpServletRequest getServletRequest() {

		return (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
	}

    public static HttpServletResponse getServletResponse() {

		return (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
	}

	private static String getJsfEl(String value) {

		return "#{" + value + "}";
	}

    public static Object getRequestAttribute(String key) {

        return ((HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false)).getAttribute(key);
    }

    public static Object getSpringBean(String name) {

        return WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()).getBean(name);
    }

    public static ExternalContext getExternalContext() {

        return FacesContext.getCurrentInstance().getExternalContext();
    }

    public static HttpSession getHttpSession(boolean create) {

        return (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(create);
    }

    public static void setManagedBeanInRequest(String beanName, Object managedBean) {

        FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(beanName, managedBean);
    }

    public static Object getRequestMapValue(String name) {

        return FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(name);
    }

    public static String getActionAttribute(ActionEvent event, String name) { //Gets the action attribute value from the specified event for the given name

        return (String) event.getComponent().getAttributes().get(name);
    }

    public static String getSessionParameter(String name) { //Get parameter value from the the session scope

        FacesContext context = FacesContext.getCurrentInstance();

        HttpServletRequest myRequest = (HttpServletRequest) context.getExternalContext().getRequest();

        HttpSession mySession = myRequest.getSession();

        return myRequest.getParameter(name);
    }

    public static Object getFAttribute(ActionEvent event, String name) { //Method to return the value specified via an f:attribute component

        return event.getComponent().getAttributes().get(name);
    }

    public static void refreshBrowser(String url) { //Method to refresh the browser to the specified url by adding a META-REFRESH tag to the response

        try{

        HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();

        if (response != null) response.setHeader("Refresh", "0; URL=" + response.encodeRedirectURL(url));

        }catch (Exception ignored) { }
    }

    public static void redirectBrowser(String url) { //Method to redirect the browser to the specified url via the ExternalContext redirect method

        try {

            FacesContext context = FacesContext.getCurrentInstance();

            if ((context != null) && (context.getExternalContext() != null)) context.getExternalContext().redirect(url);

        }catch (Exception failedRedirect) { failedRedirect.printStackTrace(); }
    }

	public static String getRealPath(String path) {

		  return (((ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext())).getRealPath(path);
	}

  public static String toString(Throwable throwable) { try {

      String sessionId= FacesUtils.getHttpSession(false).getId();

      String usuarioID= (String) FacesUtils.getHttpSession(false).getAttribute("open-usr-ID");

      String usuarioIP= (String) FacesUtils.getHttpSession(false).getAttribute("open-usr-IP");

      String usuarioTR= (String) FacesUtils.getHttpSession(false).getAttribute("open-usr-TR");

      String usuarioDATE= (String) FacesUtils.getHttpSession(false).getAttribute("open-usr-DATE");


      String info= "["+sessionId+"]["+usuarioID+"]["+usuarioTR+"]["+usuarioDATE+"]["+usuarioIP+"]";

      StringWriter sw= new StringWriter();

      PrintWriter pw= new PrintWriter(sw);

      throwable.printStackTrace(pw);

      return "--- Start Error --- "+info+" ---\r\n" + sw.toString() + "--- End Error ---\r\n";

  } catch(Exception e) { return "Error al obtener print Stack Trace de la Exception ...";  } }

}
